package com.eastfair.venueservice.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
//import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.eastfair.auth.vo.UserAccountVo;
import com.eastfair.boot.request.PageParams;
import com.eastfair.boot.service.SuperServiceImpl;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.exception.BizException;
import com.eastfair.core.utils.ExcelUtils;
import com.eastfair.database.mybatis.typehandler.TypeHandlerUtil;
import com.eastfair.home.api.HomeMsgFeign;
import com.eastfair.pay.dto.ApplyRefundDTO;
import com.eastfair.pay.dto.TransactionDTO;
import com.eastfair.pay.dto.TransactionOrderDTO;
import com.eastfair.pay.enums.*;
import com.eastfair.projectcore.enumeration.MenuAffiliationEnum;
import com.eastfair.venueservice.dao.ServiceOrderMapper;
import com.eastfair.venueservice.dto.ExhibitionServiceProviderQuery;
import com.eastfair.venueservice.dto.ServiceBookingDTO;
import com.eastfair.venueservice.dto.ServiceOrderDTO;
import com.eastfair.venueservice.entity.CreatCode;
import com.eastfair.venueservice.entity.ServiceOrder;
import com.eastfair.venueservice.enumeration.*;
import com.eastfair.venueservice.enums.ServiceOrderRefundStatus;
import com.eastfair.venueservice.exceptioncode.VenueServiceExceptionCode;
import com.eastfair.venueservice.service.*;
import com.eastfair.venueservice.vo.ExhibitionSettlementVO;
import com.eastfair.venueservice.vo.ServiceBookingVO;
import com.eastfair.venueservice.vo.ServiceOrderVO;
import com.eastfair.venueservice.vo.ServiceProviderVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 业务实现类
 * 服务订单
 * </p>
 *
 * @author dq
 * @date 2022-09-28
 */
@Slf4j
@Service
//@DS("#thread.tenant")
public class ServiceOrderServiceImpl extends SuperServiceImpl<ServiceOrderMapper, ServiceOrder> implements ServiceOrderService {

    private static final String ORDER_NUMBER_FIELD = "order_number";

    private static final int ORDER_NUMBER_LENGTH = 5;

    @Resource
    private ServiceBookingService serviceBookingService;

    @Resource
    private VenueManageUserAccountService venueManageUserAccountService;

    @Resource
    private ServiceOrderMapper serviceOrderMapper;

    @Resource
    private ServiceOrderOperateLogService serviceOrderOperateLogService;

    @Resource
    private DepositWarningService depositWarningService;

    @Resource
    private ExhibitionSettlementService exhibitionSettlementService;

    @Resource
    private VenueManageTransactionService venueManageTransactionService;

    @Resource
    private VenueManageTransactionOrderService venueManageTransactionOrderService;

    @Resource
    private VenueManageApplyRefundService venueManageApplyRefundService;

    @Resource
    private ServiceItemService serviceItemService;

    @Resource
    private VenueManageDictionaryService venueManageDictionaryService;

    @Resource
    private ExhibitionServiceProviderService exhibitionServiceProviderService;

    @Resource
    private HomeMsgFeign homeMsgFeign;

    /**
     * 处理逻辑删除相关处理
     *
     * @param modelList 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerRemoveByIdsOfLogic(Collection<ServiceOrder> modelList) {
        modelList.forEach(s -> s.setIsDeleted(BusinessConstant.YES));
        return R.successDef();
    }

    @Override
    protected R<Boolean> handlerSave(ServiceOrder model) {
        model.setProjectId(ContextUtil.getProjectId());
        model.setSubsystemId(ContextUtil.getSubSystemId());

        if (model.getOrderStatus() == null) {
            model.setOrderStatus(ServiceOrderOrderStatusEnum.NOT_SUBMIT);
        }
        if (model.getPayStatus() == null) {
            // 处理订单金额为0的情况
            BigDecimal shouldPayAmount = model.getShouldPayAmount() == null ? BigDecimal.ZERO : model.getShouldPayAmount();
            if (BigDecimal.ZERO.compareTo(shouldPayAmount) == 0) {
                model.setPayStatus(ServiceOrderPayStatusEnum.HAS_PAY);
                model.setRefundStatus(ServiceOrderRefundStatus.NO_REFUND.getCode());
                model.setPayTime(LocalDateTime.now());
                model.setActualPayAmount(BigDecimal.ZERO);
            } else {
                model.setPayStatus(ServiceOrderPayStatusEnum.NOT_PAY);
            }
        }
        if (model.getInvoiceStatus() == null) {
            model.setInvoiceStatus(ServiceOrderInvoiceStatusEnum.NOT_APPLIED);
        }
        if (model.getWorkOrderStatus() == null) {
            model.setWorkOrderStatus(ServiceOrderWorkOrderStatusEnum.NOT_DISPATCH);
        }
        if (model.getServiceReportVenueStatus() == null) {
            model.setServiceReportVenueStatus(ServiceOrderServiceReportVenueStatusEnum.NOT_NEED_REPORT);
        }
        if (StrUtil.isBlank(model.getRefundStatus())) {
            model.setRefundStatus(ServiceOrderRefundStatus.NO_REFUND.getCode());
        }
        return R.successDef();
    }

    @Override
    public Page<ServiceOrderVO> listServiceOrderVOs(PageParams<ServiceOrderDTO> pageParams) {
        log.info("listServiceOrderVOs - 分页查询服务订单列表, pageParams={}", pageParams);
        ServiceOrderDTO model = pageParams.getModel();
        Page<ServiceOrder> page = pageParams.buildPage();
        QueryWrapper<ServiceOrder> queryWrapper = createServiceOrderVOQueryWrapper(model);
        Page<ServiceOrderVO> voPage = serviceOrderMapper.listServiceOrderVOs(page, queryWrapper);
        List<ServiceOrderVO> voList = voPage.getRecords();
        if (voList == null || voList.isEmpty()) {
            return voPage;
        }
        List<Long> createByIds = voList
                .stream()
                .map(ServiceOrderVO::getCreatedBy)
                .collect(Collectors.toList());
        Map<Long, String> userMap = venueManageUserAccountService.listUserAccount(createByIds);
        voList.forEach(serviceOrderVO -> {
            String username = userMap.get(serviceOrderVO.getCreatedBy());
            serviceOrderVO.setCreatedByName(username);
            if (serviceOrderVO.getOrderStatus().eq(ServiceOrderOrderStatusEnum.SUBMIT) && serviceOrderVO.getWorkOrderStatus().eq(ServiceOrderWorkOrderStatusEnum.NOT_DISPATCH)) {
                serviceOrderVO.setIsNew(BusinessConstant.YES);
            } else {
                serviceOrderVO.setIsNew(BusinessConstant.NO);
            }
            try {
                serviceOrderVO.setPhone(TypeHandlerUtil.decrypt(serviceOrderVO.getPhone()));
            } catch (Exception e) {
                log.warn("解密失败:{}",serviceOrderVO);
            }
        });
        return voPage;
    }

    @Override
    public List<ServiceOrder> listServiceOrders(ServiceOrderDTO serviceOrderDTO) {
        log.info("listServiceOrders - 查询服务订单, serviceOrderDTO={}", serviceOrderDTO);
        QueryWrapper<ServiceOrder> queryWrapper = createServiceOrderQueryWrapper(serviceOrderDTO);
        return list(queryWrapper);
    }

    @Override
    public ServiceOrderVO getVOByOrderNumber(String orderNumber) {
        log.info("getVOByOrderNumber - 订单编号获取服务订单VO, orderNumber={}", orderNumber);
        ServiceOrder serviceOrder = getByOrderNumber(orderNumber);
        if (serviceOrder == null) {
            return null;
        }
        return BeanUtil.toBean(serviceOrder, ServiceOrderVO.class);
    }

    @Override
    public ServiceOrder getByOrderNumber(String orderNumber) {
        log.info("getByOrderNumber - 订单编号获取服务订单, orderNumber={}", orderNumber);
        ServiceOrderDTO param = new ServiceOrderDTO();
        param.setOrderNumber(orderNumber);
        List<ServiceOrder> list = listServiceOrders(param);
        if (list == null || list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    @Override
    public ServiceOrder getByRepairReportNumber(String repairReportNumber, ServiceOrderOrderSourceEnum orderOrderSourceEnum) {
        log.info("getByRepairReportNumber - 报修单号查询报修订单, repairReportNumber={}, orderOrderSourceEnum={}", repairReportNumber, orderOrderSourceEnum);
        ServiceOrderDTO query = new ServiceOrderDTO();
        query.setRepairReportNumber(repairReportNumber);
        query.setOrderSource(orderOrderSourceEnum);
        List<ServiceOrder> list = listServiceOrders(query);
        if (list == null || list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    @Override
    public List<ServiceOrder> listTimeoutNotPayServiceOrder(ServiceOrderDTO serviceOrderDTO) {
        log.info("listTimeoutNotPayServiceOrder - 查询超时为支付订单, serviceOrderDTO={}", serviceOrderDTO);
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime oneHourBefore = now.minusHours(CANCEL_TIME_OUT);
        // 查询需要超时取消的订单
        // 超时已提交且未支付的需要取消，会后结算订单，主办订单，管理费订单不需要取消
        QueryWrapper<ServiceOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(ServiceOrder::getIsDeleted, BusinessConstant.DELETE_NO)
                .eq(ServiceOrder::getPayStatus, ServiceOrderPayStatusEnum.NOT_PAY.getCode())
                .ne(ServiceOrder::getOrderStatus, ServiceOrderOrderStatusEnum.CANCEL)
                .ne(ServiceOrder::getOrderStatus, ServiceOrderOrderStatusEnum.NOT_SUBMIT)
                .eq(ServiceOrder::getOrderStatus, ServiceOrderOrderStatusEnum.SUBMIT)
                .ne(ServiceOrder::getOrderSource, ServiceOrderOrderSourceEnum.SPONSOR_ORDER)
                .ne(ServiceOrder::getIsManageExpense, BusinessConstant.YES)
                .ne(ServiceOrder::getPayStatus, ServiceOrderPayStatusEnum.SETTLE_AFTER_EXHIBITION)
                .lt(ServiceOrder::getOrderTime, oneHourBefore)
                .in(serviceOrderDTO.getBelongSystemList() != null && !serviceOrderDTO.getBelongSystemList().isEmpty(),
                        ServiceOrder::getBelongSystem, serviceOrderDTO.getBelongSystemList())
                .in(serviceOrderDTO.getOrderSourceEnumList() != null && !serviceOrderDTO.getOrderSourceEnumList().isEmpty(),
                        ServiceOrder::getOrderSource, serviceOrderDTO.getOrderSourceEnumList())
        ;
        return list(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceOrder saveServiceOrder(ServiceOrderDTO serviceOrderDTO) {
        log.info("saveServiceOrder - 保存服务订单, serviceOrderDTO={}", serviceOrderDTO);
        // 生成订单号
        String prefix = LocalDateTimeUtil.format(LocalDate.now(), "yyyyMMdd");
        String orderNumber = CreatCode.creatCode(baseMapper, ORDER_NUMBER_FIELD, ORDER_NUMBER_LENGTH, prefix);
        serviceOrderDTO.setOrderNumber(orderNumber);
        // 保存订单
        ServiceOrder serviceOrder = BeanUtil.toBean(serviceOrderDTO, ServiceOrder.class);
        save(serviceOrder);
        return serviceOrder;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceOrder updateServiceOrder(ServiceOrderDTO serviceOrderDTO) {
        log.info("updateServiceOrder - 更新订单, serviceOrderDTO={}", serviceOrderDTO);
        ServiceOrder oldServiceOrder = getByOrderNumber(serviceOrderDTO.getOrderNumber());
        ServiceOrder serviceOrder = BeanUtil.toBean(serviceOrderDTO, ServiceOrder.class);
        updateById(serviceOrder);
        // 记录修改订单金额操作日志
        serviceOrderOperateLogService.asyncLogUpdateOrderAmount(serviceOrder, oldServiceOrder);
        return serviceOrder;
    }

    @Override
    public boolean submitServiceOrder(String orderNumber) {
        log.info("submitServiceOrder - orderNumber, serviceOrderDTO={}", orderNumber);
        ServiceOrder serviceOrder = getByOrderNumber(orderNumber);
        if (serviceOrder == null) {
            throw BizException.wrap(VenueServiceExceptionCode.ORDER_NOT_EXIST.getCode(), "提交失败，订单不存在");
        }
        updateOrderStatusSubmit(serviceOrder);
        // 将订单下服务修改为已提交
        ServiceBookingDTO serviceBookingDTO = new ServiceBookingDTO();
        serviceBookingDTO.setOrderNumber(serviceOrder.getOrderNumber());
        serviceBookingDTO.setOrderStatus(ServiceBookingOrderStatusEnum.SUBMIT);
        serviceBookingDTO.setAuditState(ServiceItemAuditStateEnum.APPROVED.getCode());
        if (Objects.nonNull(serviceOrder.getOrderSource()) && serviceOrder.getOrderSource().eq(ServiceOrderOrderSourceEnum.HOME_BUILDER_REPAIR_ORDER)) {
            serviceBookingDTO.setReportSpaceStatus(ServiceBookingReportSpaceStatusEnum.REPORTED);
        }
        // 异步处理押金预警
        depositWarningService.warning(serviceOrder);
        serviceItemService.warning(serviceOrder);
        // 异步推送站内信
        if (MenuAffiliationEnum.P_COMPOSITE_PRODUCER.getCode().equals(serviceOrder.getBelongSystem())) {
            Long exhibitionManageId = serviceOrder.getExhibitionManageId();
            ExhibitionServiceProviderQuery exhibitionServiceProviderQuery = new ExhibitionServiceProviderQuery();
            exhibitionServiceProviderQuery.setExhibitionManageId(exhibitionManageId);
            exhibitionServiceProviderQuery.setServiceProviderType(ServiceProviderTypeEnum.HOME_SERVICE_PROVIDER.getCode());
            List<ServiceProviderVO> serviceProviderVOS = exhibitionServiceProviderService.queryExhibitionServiceProvider(exhibitionServiceProviderQuery);
            if (CollectionUtils.isNotEmpty(serviceProviderVOS)) {
                String content = String.format("收到来自%s的新订单，单号%s，请及时处理！", serviceOrder.getCompanyName(), orderNumber);
                homeMsgFeign.sendInnerMsgByTeamId(content, serviceProviderVOS.get(0).getId());
            }
        }
        return serviceBookingService.updateBookingServiceOrderStatus(serviceOrder,serviceBookingDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceOrder updateOrderStatusSubmit(ServiceOrder serviceOrder) {
        log.info("updateOrderStatusSubmit - 更新订单为已提交, serviceOrder={}", serviceOrder);
        if (!serviceOrder.getOrderStatus().eq(ServiceOrderOrderStatusEnum.NOT_SUBMIT)
                && !serviceOrder.getOrderStatus().eq(ServiceOrderOrderStatusEnum.CANCEL)) {
            throw BizException.wrap(VenueServiceExceptionCode.ORDER_CAN_NOT_SUBMIT.getCode(), "订单已提交，不可再提交");
        }
        serviceOrder.setOrderStatus(ServiceOrderOrderStatusEnum.SUBMIT);
        serviceOrder.setOrderTime(LocalDateTime.now());
        updateById(serviceOrder);
        return serviceOrder;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOrderStatusComplete(ServiceOrder serviceOrder) {
        log.info("updateOrderStatusComplete - 更新订单状态为已完成, serviceOrder={}", serviceOrder);
        if (ServiceOrderOrderStatusEnum.COMPLETE.eq(serviceOrder.getOrderStatus())) {
            return true;
        }
        serviceOrder.setFinishOrderTime(LocalDateTime.now());
        serviceOrder.setOrderStatus(ServiceOrderOrderStatusEnum.COMPLETE);
        return updateById(serviceOrder);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceOrder updatePayStatus(ServiceOrderDTO serviceOrderDTO) {
        log.info("updatePayStatus - 更新支付状态, serviceOrderDTO={}", serviceOrderDTO);
        ServiceOrder serviceOrder = getByOrderNumber(serviceOrderDTO.getOrderNumber());
        if (serviceOrder == null) {
            throw BizException.wrap(VenueServiceExceptionCode.ORDER_NOT_EXIST.getCode(), "订单不存在");
        }
        if (ServiceOrderPayStatusEnum.HAS_PAY.eq(serviceOrder.getPayStatus())
                && ServiceOrderPayStatusEnum.PARTIAL_PAY.eq(serviceOrderDTO.getPayStatus())) {
            throw BizException.wrap(VenueServiceExceptionCode.ORDER_PAY_ERROR.getCode(), "订单支付失败, 订单已支付完成，不可改为部分支付");
        }
        // 当前支付金额
        BigDecimal nowActualPayAmount = (serviceOrderDTO.getActualPayAmount() == null) ? BigDecimal.ZERO : serviceOrderDTO.getActualPayAmount();
        if (nowActualPayAmount == null || BigDecimal.ZERO.compareTo(nowActualPayAmount) == 0) {
            throw BizException.wrap(VenueServiceExceptionCode.PAY_AMOUNT_CAN_NOT_BE_ZERO);
        }
        // 订单目前实际支付金额
        BigDecimal actualPayAmount = serviceOrder.getActualPayAmount() == null ? BigDecimal.ZERO : serviceOrder.getActualPayAmount();
        // 订单应支付金额
        BigDecimal shouldPayAmount = serviceOrder.getShouldPayAmount() == null ? BigDecimal.ZERO : serviceOrder.getShouldPayAmount();
        actualPayAmount = actualPayAmount.add(nowActualPayAmount);
        if (actualPayAmount.compareTo(shouldPayAmount) > 0) {
            throw BizException.wrap(VenueServiceExceptionCode.ACTUAL_PAY_AMOUNT_GT_SHOULD_PAY_AMOUNT);
        }
        // 更新支付状态与退款状态
        serviceOrder.setActualPayAmount(actualPayAmount);
        if (actualPayAmount.compareTo(shouldPayAmount) >= 0) {
            serviceOrder.setPayStatus(ServiceOrderPayStatusEnum.HAS_PAY);
            serviceOrder.setRefundStatus(ServiceOrderRefundStatus.NOT_APPLIED.getCode());
        }
        if (actualPayAmount.compareTo(BigDecimal.ZERO) > 0 && actualPayAmount.compareTo(shouldPayAmount) < 0) {
            serviceOrder.setPayStatus(ServiceOrderPayStatusEnum.PARTIAL_PAY);
            serviceOrder.setRefundStatus(ServiceOrderRefundStatus.NOT_APPLIED.getCode());
        }
        serviceOrder.setPayWay(serviceOrderDTO.getPayWay());
        serviceOrder.setPayTime(LocalDateTime.now());
        updateById(serviceOrder);
        // 新增交易记录
        saveTransaction(serviceOrder, serviceOrderDTO);
        return serviceOrder;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceOrder updateRefundStatus(ServiceOrderDTO serviceOrderDTO) {
        log.info("updateRefundStatus - 更新退款状态, serviceOrderDto={}", serviceOrderDTO);
        ServiceOrder serviceOrder = getByOrderNumber(serviceOrderDTO.getOrderNumber());
        if (serviceOrder == null) {
            throw BizException.wrap(VenueServiceExceptionCode.ORDER_NOT_EXIST);
        }
        serviceOrder.setRefundStatus(serviceOrderDTO.getRefundStatus());
        // 更新订单支付状态
        ServiceOrderPayStatusEnum payStatus = ServiceOrderRefundStatus.toServiceOrderPayStatus(serviceOrderDTO.getRefundStatus());
        if (payStatus != null) {
            serviceOrder.setPayStatus(payStatus);
        }
        serviceOrder.setRefundTime(LocalDateTime.now());
        serviceOrder.setRefundWay(serviceOrderDTO.getRefundWay());
        // 计算退款金额
        BigDecimal refundAmount = serviceOrder.getRefundAmount() == null ? BigDecimal.ZERO : serviceOrder.getRefundAmount();
        if (serviceOrderDTO.getRefundAmount() != null && ServiceOrderRefundStatus.AUTH_SUCESS.eq(serviceOrderDTO.getRefundStatus())) {
            refundAmount = refundAmount.add(serviceOrderDTO.getRefundAmount());
            serviceOrder.setRefundAmount(refundAmount);
        }
        updateById(serviceOrder);
        return serviceOrder;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceOrder updateInvoiceStatus(ServiceOrderDTO serviceOrderDTO) {
        log.info("updateInvoiceStatus - 更新开票状态, serviceOrderDTO={}", serviceOrderDTO);
        ServiceOrder serviceOrder = getByOrderNumber(serviceOrderDTO.getOrderNumber());
        if (serviceOrder == null) {
            throw BizException.wrap(VenueServiceExceptionCode.ORDER_NOT_EXIST);
        }
        serviceOrder.setInvoiceStatus(serviceOrderDTO.getInvoiceStatus());
        serviceOrder.setInvoiceAmount(serviceOrderDTO.getInvoiceAmount());
        serviceOrder.setInvoiceCode(serviceOrderDTO.getInvoiceCode());
        serviceOrder.setInvoiceNumber(serviceOrderDTO.getInvoiceNumber());
        updateById(serviceOrder);
        return serviceOrder;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean applyServiceOrderRefund(ServiceOrderDTO serviceOrderDTO) {
        log.info("applyServiceOrderRefund - 发起订单退款申请, serviceOrderDTO={}", serviceOrderDTO);
        BigDecimal actualPayAmount = serviceOrderDTO.getActualPayAmount();
        ServiceOrderPayStatusEnum payStatus = serviceOrderDTO.getPayStatus();
        if (!ServiceOrderPayStatusEnum.HAS_PAY.eq(payStatus) && !ServiceOrderPayStatusEnum.PARTIAL_PAY.eq(payStatus)) {
            log.warn("acceptApplyRefund - 不是已付款，部分付款 的无需退款");
            // 不是已付款，部分付款 的无需退款
            return false;
        }
        if (!ServiceOrderRefundStatus.NOT_APPLIED.eq(serviceOrderDTO.getRefundStatus()) && !ServiceOrderRefundStatus.AUTH_FAIL.eq(serviceOrderDTO.getRefundStatus())) {
            log.warn("acceptApplyRefund - 不是未申请退款的，退款申请驳回的无需退款");
            // 不是未申请退款的，退款申请驳回的无需退款
            return false;
        }
        if (actualPayAmount.equals(BigDecimal.ZERO)) {
            log.warn("acceptApplyRefund - 支付金额为0，无需退款");
            // 支付金额为0，无需退款
            return false;
        }
        // 更新订单退款状态为已申请
//        ServiceOrderDTO applyRefundDTO = new ServiceOrderDTO();
//        applyRefundDTO.setOrderNumber(serviceOrderDTO.getOrderNumber());
//        applyRefundDTO.setRefundStatus(ServiceOrderRefundStatus.APPLIED.getCode());
//        updateRefundStatus(applyRefundDTO);
        // 发起支付系统退款
        acceptApplyRefund(serviceOrderDTO);
        return true;
    }

    @Override
    public boolean saveTransaction(ServiceOrder serviceOrder, ServiceOrderDTO serviceOrderDTO) {
        log.info("saveTransaction - 生成交易记录, serviceOrder={}, serviceOrderDTO={}", serviceOrder, serviceOrderDTO);
        TransactionDTO transactionDTO = new TransactionDTO();
        transactionDTO.setExhibitionId(serviceOrder.getExhibitionManageId());
        transactionDTO.setExhibitionName(serviceOrder.getExhibitionManageName());
        transactionDTO.setSpaceName(serviceOrder.getSpaceName());
        transactionDTO.setSiteName(serviceOrder.getSiteName());
        transactionDTO.setServiceProviderId(serviceOrder.getCompanyId());
        transactionDTO.setServiceProviderName(serviceOrder.getCompanyName());
        transactionDTO.setServiceProviderType(serviceOrder.getCompanyType());
        transactionDTO.setOrderType(InvoiceApplyBusinessTypeEnum.D.getCode());
        transactionDTO.setOrderNum(serviceOrder.getOrderNumber());
        transactionDTO.setOrderAmount(serviceOrderDTO.getActualPayAmount());
        transactionDTO.setOrderTime(LocalDateTime.now());
        transactionDTO.setTransactionType(TranstionTypeEnum.PAYED.getCode());
        transactionDTO.setTransactionState(TransactionStatusEnum.PAYED.getCode());
        transactionDTO.setPayer(serviceOrderDTO.getPayer());
        transactionDTO.setPayType(serviceOrderDTO.getPayWay());
        transactionDTO.setSystemScene(ContextUtil.getSystemScene());
        return venueManageTransactionService.save(transactionDTO);
    }

    @Override
    public boolean saveTransactionOrder(ServiceOrderDTO serviceOrderDTO) {
        log.info("saveTransactionOrder - 生成支付系统交易订单, serviceOrderDTO={}", serviceOrderDTO);
        TransactionOrderDTO transactionOrderDTO = ServiceOrderService.toTransactionOrder(serviceOrderDTO);
        return venueManageTransactionOrderService.save(transactionOrderDTO);
    }

    @Override
    public boolean acceptApplyRefund(ServiceOrderDTO serviceOrderDTO) {
        // 发起支付中心退款
        ApplyRefundDTO applyRefundDTO = new ApplyRefundDTO();
        applyRefundDTO.setCutomerId(serviceOrderDTO.getCompanyId());
        applyRefundDTO.setCutomerName(serviceOrderDTO.getCompanyName());
        applyRefundDTO.setRefundApplyAmount(serviceOrderDTO.getActualPayAmount());
        applyRefundDTO.setExhibitionId(serviceOrderDTO.getExhibitionManageId());
        applyRefundDTO.setExhibitionName(serviceOrderDTO.getExhibitionManageName());
        //  退款人联系方式
        Long userId = ContextUtil.getUserId();
        if (userId != null) {
            UserAccountVo userAccountVo = venueManageUserAccountService.findSimpleById(userId);
            applyRefundDTO.setApplicantId(userId);
            applyRefundDTO.setApplicantName(userAccountVo.getRealName());
            applyRefundDTO.setApplicantConcat(userAccountVo.getMobile());
        }
        applyRefundDTO.setBusinessId(serviceOrderDTO.getId());
        applyRefundDTO.setBusinessNum(serviceOrderDTO.getOrderNumber());
        applyRefundDTO.setBusinessType(ApplyRefundBusinessTypeEnum.D.getCode());
        applyRefundDTO.setRefundClassify(RefundClassifyEnum.ORDER_CANCEL.getCode());
        applyRefundDTO.setSystemCode(serviceOrderDTO.getSystemCode());
        return venueManageApplyRefundService.acceptApplyRefund(applyRefundDTO);
    }

    @Override
    public boolean existServiceOrderByCompanyId(Long companyId) {
        ServiceOrderDTO serviceOrderDTO = new ServiceOrderDTO();
        serviceOrderDTO.setCompanyId(companyId);
        List<ServiceOrder> serviceOrders = listServiceOrders(serviceOrderDTO);
        if (serviceOrders == null || serviceOrders.isEmpty()) {
            return false;
        }
        for (ServiceOrder serviceOrder : serviceOrders) {
            if (!ServiceOrderOrderStatusEnum.CANCEL.eq(serviceOrder.getOrderStatus())) {
                return true;
            }
        }
        return false;
    }

    @Override
    public Map<String, Object> orderDataAnalysis(ServiceOrderDTO serviceOrderDTO) {
        LocalDate now = LocalDate.now();
        LocalDate startDate = now.minusDays(6);
        List<LocalDate> betweenDate = getBetweenDate(startDate, now);
        Map<String, Object> nums = baseMapper.queryNumOfOrderAndService(serviceOrderDTO);
        List<Map<String, Object>> trend = baseMapper.queryOrderTrend(serviceOrderDTO);
        List<Map<String, Object>> categoryStatistics = baseMapper.queryCategoryStatistics(serviceOrderDTO);
        List<Object> numList = new ArrayList<>();
        List<Object> amountList = new ArrayList<>();
        List<Object> data = new ArrayList<>();
        for (LocalDate localDate : betweenDate) {
            data.add(localDate.toString().substring(5));
            boolean flag = false;
            for (Map<String, Object> map : trend) {
                LocalDate returnDate = LocalDate.parse(map.get("date").toString());
                if (localDate.compareTo(returnDate) == 0) {
                    numList.add(map.get("num"));
                    amountList.add(map.get("amount"));
                    flag = true;
                    break;
                }
            }
            if (flag) {
                continue;
            }
            numList.add(0);
            amountList.add(0);
        }
        nums.put("categoryStatistics", categoryStatistics);
        Map<String, Object> numTrend = new HashMap<>(2);
        numTrend.put("date", data);
        numTrend.put("value", numList);
        nums.put("numTrend", numTrend);
        Map<String, Object> amountTrend = new HashMap<>(2);
        amountTrend.put("date", data);
        amountTrend.put("value", amountList);
        nums.put("amountTrend", amountTrend);
        return nums;
    }

    @Override
    public Map<String, Object> orderAmountTrend(ServiceOrderDTO serviceOrderDTO) {
        LocalDate endDate = serviceOrderDTO.getCreateTimeEnd().toLocalDate();
        LocalDate startDate = serviceOrderDTO.getCreateTimeStart().toLocalDate();
        List<LocalDate> betweenDate = getBetweenDate(startDate, endDate);
        List<Map<String, Object>> trend = baseMapper.queryOrderTrendByCreateTime(serviceOrderDTO);
        List<Object> amountList = new ArrayList<>();
        List<Object> data = new ArrayList<>();
        for (LocalDate localDate : betweenDate) {
            data.add(localDate.toString().substring(5));
            boolean flag = false;
            for (Map<String, Object> map : trend) {
                LocalDate returnDate = LocalDate.parse(map.get("date").toString());
                if (localDate.compareTo(returnDate) == 0) {
                    amountList.add(map.get("amount"));
                    flag = true;
                    break;
                }
            }
            if (flag) {
                continue;
            }
            amountList.add(0);
        }
        Map<String, Object> amountTrend = new HashMap<>(2);
        amountTrend.put("date", data);
        amountTrend.put("value", amountList);
        return amountTrend;
    }

    @Override
    public Map<String, Object> orderNumTrend(ServiceOrderDTO serviceOrderDTO) {
        LocalDate endDate = serviceOrderDTO.getCreateTimeEnd().toLocalDate();
        LocalDate startDate = serviceOrderDTO.getCreateTimeStart().toLocalDate();
        List<LocalDate> betweenDate = getBetweenDate(startDate, endDate);
        List<Map<String, Object>> trend = baseMapper.queryOrderTrendByCreateTime(serviceOrderDTO);
        List<Object> numList = new ArrayList<>();
        List<Object> data = new ArrayList<>();
        for (LocalDate localDate : betweenDate) {
            data.add(localDate.toString().substring(5));
            boolean flag = false;
            for (Map<String, Object> map : trend) {
                LocalDate returnDate = LocalDate.parse(map.get("date").toString());
                if (localDate.compareTo(returnDate) == 0) {
                    numList.add(map.get("num"));
                    flag = true;
                    break;
                }
            }
            if (flag) {
                continue;
            }
            numList.add(0);
        }
        Map<String, Object> numTrend = new HashMap<>(2);
        numTrend.put("date", data);
        numTrend.put("value", numList);
        return numTrend;
    }

    @Override
    public List<ExhibitionSettlementVO> queryBuilder(Long exhibitionManageId) {
        return baseMapper.queryBuilder(exhibitionManageId);
    }

    @Override
    public ServiceOrderVO queryTotalDiscountAmount(Set<String> orderNumbers) {
        ServiceOrderVO serviceOrderVO = baseMapper.queryTotalDiscountAmount(orderNumbers);
        if (Objects.isNull(serviceOrderVO)) {
            ServiceOrderVO newEntity = new ServiceOrderVO();
            newEntity.setDiscountAmount(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP));
            return newEntity;
        }
        return baseMapper.queryTotalDiscountAmount(orderNumbers);
    }

    @Override
    public List<ServiceOrderVO> packageServiceBookingList(List<ServiceOrder> serviceOrderList) {
        // 订单编号查询订单下预定的服务列表
        List<String> orderNumberList = serviceOrderList
                .stream()
                .map(ServiceOrder::getOrderNumber)
                .collect(Collectors.toList());
        Map<String, List<ServiceBookingVO>> orderServiceBookingMap = serviceBookingService.getServiceBookingMapByOrderNumber(orderNumberList);
        // 转为订单VO列表
        return serviceOrderList
                .stream()
                .map(serviceOrder -> {
                    ServiceOrderVO serviceOrderVO = BeanUtil.toBean(serviceOrder, ServiceOrderVO.class);
                    List<ServiceBookingVO> serviceBookingList = orderServiceBookingMap.get(serviceOrderVO.getOrderNumber());
                    serviceOrderVO.setServiceBookingList(serviceBookingList);
                    return serviceOrderVO;
                })
                .collect(Collectors.toList());
    }

    @Override
    public void exportServiceOrder(ServiceOrderDTO serviceOrderDTO, HttpServletResponse response) throws IOException {
        log.info("exportServiceOrder - 订单导出, serviceOrderDTO={}", serviceOrderDTO);
        PageParams<ServiceOrderDTO> pageParams = new PageParams<>();
        pageParams.setSize(5000);
        pageParams.setCurrent(1);
        Page<ServiceOrder> page = pageParams.buildPage();
        QueryWrapper<ServiceOrder> queryWrapper = createServiceOrderVOQueryWrapper(serviceOrderDTO);
        Page<ServiceOrderVO> voPage = serviceOrderMapper.listServiceOrderVOs(page, queryWrapper);
        // 数据字典
        Map<String, String> orderStatusDict = venueManageDictionaryService.queryDictMap("BUILDER_SERVICE_ORDER_ORDER_STATUS");
        Map<String, String> payStatusDict = venueManageDictionaryService.queryDictMap("SERVICE_ORDER_PAY_STATUS");
        Map<String, String> payWayDict = venueManageDictionaryService.queryDictMap("SERVICE_ORDER_PAY_WAY");

        List<ServiceOrderVO> voList = voPage.getRecords();
        if (voList == null || voList.isEmpty()) {
            throw BizException.wrap(1001, "无导出数据");
        }
        List<Map<String, Object>> rows = new ArrayList<>();
        for (ServiceOrderVO serviceOrderVO : voList) {
            TreeMap<String, Object> map = new TreeMap<>((o1, o2) -> 1);
            map.put("订单编号", serviceOrderVO.getOrderNumber());
            map.put("订单总金额（¥）", serviceOrderVO.getShouldPayAmount() + "");
            map.put("附加费金额（¥）", serviceOrderVO.getSurcharge() + "");
            String orderStatusValue = null;
            ServiceOrderOrderStatusEnum orderStatus = serviceOrderVO.getOrderStatus();
            if (orderStatus != null) {
                orderStatusValue = orderStatusDict.get(orderStatus.getCode());
            }
            map.put("订单状态", orderStatusValue);
            String payStatusValue = null;
            ServiceOrderPayStatusEnum payStatus = serviceOrderVO.getPayStatus();
            if (payStatus != null) {
                payStatusValue = payStatusDict.get(payStatus.getCode());
            }
            map.put("支付状态", payStatusValue);
            String payWayValue = null;
            String payWay = serviceOrderVO.getPayWay();
            if (StrUtil.isNotBlank(payWay)) {
                payWayValue = payWayDict.get(payWay);
            }
            map.put("支付方式", payWayValue);
            map.put("订单时间", serviceOrderVO.getOrderTime());
            rows.add(map);
        }
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=订单.xlsx");
        try (ServletOutputStream out = response.getOutputStream()) {
            ExcelUtils.export(rows, out);
        }
    }

    /**
     * 创建ServiceOrderVO的查询.
     *
     * @param model ServiceOrderDTO.
     * @return QueryWrapper.
     */
    private QueryWrapper<ServiceOrder> createServiceOrderVOQueryWrapper(ServiceOrderDTO model) {
        QueryWrapper<ServiceOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .eq("so.is_deleted", BusinessConstant.DELETE_NO)
                .eq(model.getId() != null, "so.id", model.getId())
                .eq(model.getExhibitionManageId() != null, "so.exhibition_manage_id", model.getExhibitionManageId())
                .eq(model.getServiceProviderId() != null, "ec.service_provider_id", model.getServiceProviderId())
                .eq(model.getCompanyId() != null, "so.company_id", model.getCompanyId())
                .like(StrUtil.isNotBlank(model.getCompanyName()), "so.company_name", model.getCompanyName())
                .like(StrUtil.isNotBlank(model.getOrderNumber()), "so.order_number", model.getOrderNumber())
                .eq(model.getOrderStatus() != null, "so.order_status", model.getOrderStatus())
                .eq(model.getOrderSource() != null, "so.order_source", model.getOrderSource())
                .eq(model.getPayStatus() != null, "so.pay_status", model.getPayStatus())
                .like(StrUtil.isNotBlank(model.getSpaceName()), "so.space_name", model.getSpaceName())
                .like(StrUtil.isNotBlank(model.getSiteName()), "so.site_name", model.getSiteName())
                .like(StrUtil.isNotBlank(model.getExhibitorName()), "so.exhibitor_name", model.getExhibitorName())
                .eq(model.getWorkOrderStatus() != null, "so.work_order_status", model.getWorkOrderStatus())
                .eq(StrUtil.isNotBlank(model.getPayWay()), "so.pay_way", model.getPayWay())
                .eq(model.getInvoiceStatus() != null, "so.invoice_status", model.getInvoiceStatus())
                .like(StrUtil.isNotBlank(model.getInvoiceCode()), "so.invoice_code", model.getInvoiceCode())
                .like(StrUtil.isNotBlank(model.getInvoiceNumber()), "so.invoice_number", model.getInvoiceNumber())
                .eq(model.getIsManageExpense() != null, "so.is_manage_expense", model.getIsManageExpense())
                .in(model.getOrderSourceList() != null && !model.getOrderSourceList().isEmpty(), "so.order_source", model.getOrderSourceList())
                .in(model.getBelongSystemList() != null && !model.getBelongSystemList().isEmpty(), "so.belong_system", model.getBelongSystemList())
                .in(model.getSpaceCodeList() != null && !model.getSpaceCodeList().isEmpty(), "so.space_code", model.getSpaceCodeList())
                // 不能把加班订单查出来
                .ne("so.order_source", ServiceOrderOrderSourceEnum.WORK_OVERTIME_ORDER)
        ;
        // 综合服务不展示未提交的订单
        List<String> belongSystemList = model.getBelongSystemList();
        if (belongSystemList != null && !belongSystemList.isEmpty() && belongSystemList.contains(MenuAffiliationEnum.P_COMPOSITE_VENUE.getCode())) {
            queryWrapper.ne("so.order_status", ServiceOrderOrderStatusEnum.NOT_SUBMIT);
        }
        return queryWrapper;
    }

    /**
     * 创建ServiceOrder的查询
     *
     * @param model ServiceOrderDTO.
     * @return QueryWrapper.
     */
    private QueryWrapper<ServiceOrder> createServiceOrderQueryWrapper(ServiceOrderDTO model) {
        QueryWrapper<ServiceOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(ServiceOrder::getIsDeleted, BusinessConstant.DELETE_NO)
                .eq(model.getExhibitionManageId() != null, ServiceOrder::getExhibitionManageId, model.getExhibitionManageId())
                .eq(StrUtil.isNotBlank(model.getOrderNumber()), ServiceOrder::getOrderNumber, model.getOrderNumber())
                .eq(model.getCompanyId() != null, ServiceOrder::getCompanyId, model.getCompanyId())
                .eq(model.getOrderStatus() != null, ServiceOrder::getOrderStatus, model.getOrderStatus())
                .eq(model.getPayStatus() != null, ServiceOrder::getPayStatus, model.getPayStatus())
                .eq(StrUtil.isNotBlank(model.getPayWay()), ServiceOrder::getPayWay, model.getPayWay())
                .eq(model.getInvoiceStatus() != null, ServiceOrder::getInvoiceStatus, model.getInvoiceStatus())
                .eq(StrUtil.isNotBlank(model.getRepairReportNumber()), ServiceOrder::getRepairReportNumber, model.getRepairReportNumber())
                .eq(model.getOrderSource() != null, ServiceOrder::getOrderSource, model.getOrderSource())
                .ne(ServiceOrder::getOrderSource, ServiceOrderOrderSourceEnum.WORK_OVERTIME_ORDER)
                .eq(model.getIsManageExpense() != null, ServiceOrder::getIsManageExpense, model.getIsManageExpense())
                .eq(model.getExhibitorId() != null, ServiceOrder::getExhibitorId, model.getExhibitorId())
                .in(model.getExhibitorIdList() != null && !model.getExhibitorIdList().isEmpty(), ServiceOrder::getExhibitorId, model.getExhibitorIdList())
        ;
        return queryWrapper;
    }

    /**
     * 获取一段时间的每一天日期或者月份
     * 开始时间要小于结束时间  时间格式  日 2022-06-12   月 2022-06
     *
     * @param startDate
     * @param endDate
     * @return
     * @throws Exception
     */
    public List<LocalDate> getBetweenDate(LocalDate startDate, LocalDate endDate) {
        List<LocalDate> list = new ArrayList<>(8);
        long distance = ChronoUnit.DAYS.between(startDate, endDate);
        Stream.iterate(startDate, d -> d.plusDays(1)).limit(distance + 1).forEach(list::add);
        return list;
    }
}
